//! `std::process` 模块的测试用例
//!
//! 本文件包含对 `std::process` 中创建和管理子进程的功能的测试。
//! 主要测试 `Command` 结构体。

#[cfg(test)]
mod tests {
    use std::io::{Read, Write};
    use std::process::{Command, Stdio};

    /// 测试运行一个简单的外部命令并检查其退出状态
    #[test]
    fn test_command_status() {
        // 使用 `echo` 命令，它在 Unix 和 Windows (通过 cmd.exe) 上都可用
        let mut cmd = if cfg!(target_os = "windows") {
            let mut c = Command::new("cmd");
            c.args(&["/C", "echo hello"]);
            c
        } else {
            let mut c = Command::new("echo");
            c.arg("hello");
            c
        };

        let status = cmd.status().expect("Failed to execute command");

        // `echo` 命令应该成功退出
        assert!(status.success());
    }

    /// 测试捕获子进程的标准输出
    #[test]
    fn test_command_output() {
        let mut cmd = if cfg!(target_os = "windows") {
            let mut c = Command::new("cmd");
            c.args(&["/C", "echo rust test"]);
            c
        } else {
            let mut c = Command::new("echo");
            c.arg("rust test");
            c
        };

        // `output()` 方法会运行命令并捕获其标准输出和标准错误
        let output = cmd.output().expect("Failed to execute command");

        assert!(output.status.success());

        // 将 stdout 的字节转换为字符串
        let stdout_str = String::from_utf8(output.stdout).unwrap();
        // 注意：Windows 的 `echo` 会在末尾添加 `\r\n`
        assert_eq!(stdout_str.trim(), "rust test");
    }

    /// 测试通过管道与子进程交互
    #[test]
    fn test_command_piping() {
        // 我们将使用 `cat` (Unix) 或 `findstr .` (Windows) 作为子进程，
        // 它会回显我们发送给它的任何内容。
        let mut cmd = if cfg!(target_os = "windows") {
            let mut c = Command::new("cmd");
            c.args(&["/C", "findstr", "."]);
            c
        } else {
            Command::new("cat")
        };

        // 配置管道
        let mut child = cmd
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()
            .expect("Failed to spawn child process");

        // 获取子进程的 stdin 和 stdout
        let mut stdin = child.stdin.take().expect("Failed to open stdin");
        let mut stdout = child.stdout.take().expect("Failed to open stdout");

        // 在一个单独的线程中写入子进程的 stdin，以避免死锁
        let write_thread = std::thread::spawn(move || {
            stdin.write_all(b"data through pipe").unwrap();
        });

        // 从子进程的 stdout 读取数据
        let mut output = String::new();
        stdout.read_to_string(&mut output).unwrap();

        // 等待子进程结束
        let status = child.wait().expect("Child process wasn't running");
        assert!(status.success());

        write_thread.join().unwrap();

        assert_eq!(output.trim(), "data through pipe");
    }

    /// 测试设置子进程的工作目录和环境变量
    #[test]
    fn test_command_env_and_dir() {
        // 这个测试在 Unix 上使用 `pwd` 和 `printenv`
        if cfg!(unix) {
            let temp_dir = tempfile::tempdir().unwrap();
            let temp_path = temp_dir.path();

            let output = Command::new("sh")
                .arg("-c")
                .arg("echo $MY_VAR; pwd")
                .current_dir(temp_path) // 设置工作目录
                .env("MY_VAR", "test_value") // 设置环境变量
                .output()
                .unwrap();

            let stdout = String::from_utf8(output.stdout).unwrap();
            let lines: Vec<_> = stdout.trim().split('\n').collect();

            assert_eq!(lines[0], "test_value");
            assert_eq!(lines[1], temp_path.to_str().unwrap());
        }
    }
}
